#####################################################################
# DONSEE ID CARD SDK FOR PYTHON
# AUTHOR: zengkai001@qq.com
# DATE: 2025-02-08
# Reference: DONSEE SDK for Python
#####################################################################
from pathlib import Path
# -*- coding : utf-8 -*-
# 本Python读取身份证信息的demo支持的型号有：EST-100、EST-100GS、EST-100G、EST-100U、EST-200G、EST-J13X等系列身份证社保卡读卡器。
import ctypes
from ctypes import c_char_p, c_int, c_long, create_string_buffer, byref

id_dev_name = b"USB"
dll_path = str(Path(__file__).parent.parent / 'PYTHON_SDK' / 'libdonsee.so')

id_image_path = b"photo.jpg"


############################################################################################
# typedef struct
# {
# 	char name[120];			   /*中文姓名*/
# 	char ENfullname[420];	   /*英文姓名*/
# 	char ENfullnameOther[120]; /*英文姓名备用*/
# 	char sex[12];			   /*性别*/
# 	char people[30];		   /*民族*/
# 	char address[240];		   /*地址*/
# 	char birthday[60];		   /*出生日期（YYYYMMDD）*/
# 	char signdate[60];		   /*发证日期（YYYYMMDD）*/
# 	char validterm[60];		   /*有效日期（YYYYMMDD）*/
# 	char number[150];		   /*证件号码*/
# 	char organs[150];		   /*发证机关(或外国人永久居住证-当次申请受理机关)*/
# 	char Nationality[60];	   /*国籍*/
# 	char Photo[2560];		   /*读取二代证电子信息时保存照片数据信息*/
# 	char Other[200];		   /*其他*/
# 	char passNu[75];		   /*通行证号*/
# 	char signCount[24];		   /*签发数次*/
# 	char certVersion[24];	   /*证件版本*/
# 	char certType[18];		   /*卡片类型："0" 居民身份证, "I" 2017版外国人永居证, "Y" 2023新版外国人永居证, "J" 港澳台居民居住证*/
# 	char changCount[18];	   /*换证次数*/
# 	char oldNumber[60];		   /*既往版本永居证号码*/
# 	char figData[2560];		   /*指纹信息*/
# } IDINFO;
############################################################################################
# 定义身份证结构体
class IDINFO(ctypes.Structure):
    _fields_ = [
        ('name', ctypes.c_char * 120),  # 姓名
        ('ENfullname', ctypes.c_char * 420),  # 英文姓名
        ('ENfullnameOther', ctypes.c_char * 120),  # 英文姓名备用
        ('sex', ctypes.c_char * 12),  # 性别
        ('people', ctypes.c_char * 30),  # 民族
        ('address', ctypes.c_char * 240),  # 地址
        ('birthday', ctypes.c_char * 60),  # 出生日期
        ('signdate', ctypes.c_char * 60),  # 发证日期
        ('validterm', ctypes.c_char * 60),  # 有效日期
        ('number', ctypes.c_char * 150),  # 证件号码
        ('organs', ctypes.c_char * 150),  # 发证机关
        ('Nationality', ctypes.c_char * 60),  # 国籍
        ('Photo', ctypes.c_char * 2560),  # 照片数据
        ('Other', ctypes.c_char * 200),  # 其他
        ('passNu', ctypes.c_char * 75),  # 通行证号
        ('signCount', ctypes.c_char * 24),  # 签发次数
        ('certVersion', ctypes.c_char * 24),  # 证件版本
        ('certType', ctypes.c_char * 18),  # 卡片类型
        ('changCount', ctypes.c_char * 18),  # 换证次数
        ('oldNumber', ctypes.c_char * 60),  # 旧证件号码
        ('figData', ctypes.c_char * 2560),  # 指纹信息
    ]

############################################################################################
# typedef struct
# {
# 	char name[40];		   /*姓名*/
# 	char sex[10];		   /*性别*/
# 	char nation[20];	   /*民族*/
# 	char birthday[50];	   /*出生日期（YYYYMMDD）*/
# 	char signdate[50];	   /*发证日期（YYYYMMDD）*/
# 	char validterm[50];	   /*有效日期（YYYYMMDD）*/
# 	char cardnumber[40];   /*卡号*/
# 	char idnumber[40];	   /*社会保障号码(身份证号)*/
# 	char city[64];		   /*城市代码*/
# 	char cardveVrsion[8];  /*社保卡版本*/
# 	char identityCode[64]; /*卡识别码*/
# 	char szTerminalNo[32]; /*SAM卡识别号*/
# 	char Other[200];	   /*其他*/
# } SSCard_IDINFO;
############################################################################################
# 定义社保卡结构体
class SSCard_IDINFO(ctypes.Structure):
    _fields_ = [
        ('name', ctypes.c_char * 40),  # 姓名
        ('sex', ctypes.c_char * 10),  # 性别
        ('nation', ctypes.c_char * 20),  # 民族
        ('birthday', ctypes.c_char * 50),  # 出生日期
        ('signdate', ctypes.c_char * 50),  # 发证日期
        ('validterm', ctypes.c_char * 50),  # 有效日期
        ('cardnumber', ctypes.c_char * 40),  # 社保卡卡号
        ('idnumber', ctypes.c_char * 40),  # 社会保障号码
        ('city', ctypes.c_char * 64),  # 城市代码
        ('cardveVrsion', ctypes.c_char * 8),  # 社保卡版本
        ('identityCode', ctypes.c_char * 64),  # 卡识别码
        ('szTerminalNo', ctypes.c_char * 32),  # SAM卡识别号
        ('Other', ctypes.c_char * 200),  # 其他
    ]


class IdReader:
    def __init__(self, library_path=dll_path):
        self.dev_name = c_char_p(id_dev_name)
        self.path = c_char_p(id_image_path)
        self.id_dev = ctypes.CDLL(library_path)
        self.id_handle = None
        self.open_device()

    def open_device(self):
        """打开设备"""
        self.id_handle = self.id_dev.Donsee_Open(self.dev_name)
        if self.id_handle == 0:
            print("连接读卡器成功")
            self.Donsee_Beep()
        else:
            print("连接读卡器失败")
            self.id_handle = None

    def close_device(self):
        """关闭设备"""
        if self.id_handle == 0:
            self.id_dev.Donsee_Close()
            self.id_handle = None
            print("设备关闭成功")
        else:
            print("设备未打开，无需关闭")

    def Donsee_Beep(self):
        """读卡器蜂鸣"""
        self.id_dev.Donsee_Beep()

    def get_msg(self):
        """读身份证"""
        if self.id_handle != 0:
            return (self.id_handle,)

        self.id_dev.Donsee_ReadIDCard.argtypes = [c_int, c_int, c_char_p, ctypes.POINTER(IDINFO), c_char_p]
        self.id_dev.Donsee_ReadIDCard.restype = c_long

        idinfo = IDINFO()
        pErrMsg = create_string_buffer(1024)
        ret = self.id_dev.Donsee_ReadIDCard(0, 1, self.path, byref(idinfo), pErrMsg)
        # 第一个参数设置身份证读卡类型：0，文本信息；1，文本+照片；2，文本+照片+指纹

        id_msg_str = {'name': '', 'gender': '', 'birth': '', 'idnum': ''}
        if ret == 0:
            self.Donsee_Beep()
            id_msg_str['name'] = idinfo.name.decode('utf-8')
            id_msg_str['gender'] = idinfo.sex.decode('utf-8')
            id_msg_str['birth'] = idinfo.birthday.decode('utf-8')
            id_msg_str['idnum'] = idinfo.number.decode('utf-8')
            print(f'身份证读取成功，姓名：{idinfo.name.decode("utf-8")}，身份证号码：{idinfo.number.decode("utf-8")}')
            return (ret, id_msg_str, id_image_path.decode('utf-8') if isinstance(id_image_path, bytes) else id_image_path)
        else:
            print(pErrMsg.value.decode("utf-8"))
            return (ret, id_msg_str, id_image_path.decode('utf-8') if isinstance(id_image_path, bytes) else id_image_path)


    def get_msg_sicard(self):
        """读社保卡"""
        if self.id_handle != 0:
            return (self.id_handle,)

        self.id_dev.Donsee_ReadSSCard.argtypes = [c_int, ctypes.POINTER(SSCard_IDINFO), c_char_p]
        self.id_dev.Donsee_ReadSSCard.restype = c_long

        sscardInfo = SSCard_IDINFO()
        pErrMsg = create_string_buffer(1024)
        ret = self.id_dev.Donsee_ReadSSCard(0x11, byref(sscardInfo), pErrMsg)

        id_msg_str = {'name': '', 'sex': '', 'birth': '', 'idnumber': ''}
        if ret == 0:
            self.Donsee_Beep()
            id_msg_str['name'] = sscardInfo.name.decode('utf-8')
            id_msg_str['sex'] = sscardInfo.sex.decode('utf-8')
            id_msg_str['nation'] = sscardInfo.nation.decode('utf-8')
            id_msg_str['birthday'] = sscardInfo.birthday.decode('utf-8')
            id_msg_str['signdate'] = sscardInfo.signdate.decode('utf-8')
            id_msg_str['validterm'] = sscardInfo.validterm.decode('utf-8')
            id_msg_str['idnumber'] = sscardInfo.idnumber.decode('utf-8')
            id_msg_str['city'] = sscardInfo.city.decode('utf-8')
            id_msg_str['cardveVrsion'] = sscardInfo.cardveVrsion.decode('utf-8')
            return (ret, id_msg_str)
        else:
            print(pErrMsg.value.decode("utf-8"))
            return (ret, id_msg_str)

    def get_msg_bankcard(self):
        """读银行卡"""
        if self.id_handle != 0:
            return (self.id_handle,)

        self.id_dev.Donsee_GetBankCardNo.argtypes = [c_char_p]
        self.id_dev.Donsee_GetBankCardNo.restype = c_long

        bank_card_no = create_string_buffer(128)
        ret = self.id_dev.Donsee_GetBankCardNo(bank_card_no)

        if ret == 0:
            self.Donsee_Beep()
            bank_card_no_str = bank_card_no.value.decode('utf-8')
            print(f'银行卡读取成功，卡号：{bank_card_no_str}')
            return (ret, bank_card_no_str)
        else:
            print("读取银行卡号失败")
            return (ret, "")

    def get_donsee_version_and_beep(self):
        """获取版本信息并蜂鸣"""
        if self.id_handle != 0:
            return (self.id_handle,)

        version_buffer = create_string_buffer(128)
        ret = self.id_dev.Donsee_Version(version_buffer)

        if ret == 0:
            self.Donsee_Beep()
            version_info = version_buffer.value.decode('utf-8')
            print(f'获取版本信息成功：{version_info}')
            return version_info
        else:
            print("获取版本信息失败")
            return ""

    def get_msg_m1card(self, block=5, key="FFFFFFFFFFFF", key_mode=0x60):
        """读取M1卡信息"""
        if self.id_handle != 0:
            return (self.id_handle,)

        # 定义函数签名
        self.id_dev.Donsee_ICRequest.argtypes = []
        self.id_dev.Donsee_ICRequest.restype = c_long
        
        self.id_dev.Donsee_ICAnticoll.argtypes = [c_char_p]
        self.id_dev.Donsee_ICAnticoll.restype = c_long
        
        self.id_dev.Donsee_ICSelect.argtypes = [c_int]
        self.id_dev.Donsee_ICSelect.restype = c_long
        
        self.id_dev.Donsee_M1VerifyPass.argtypes = [c_int, c_int, c_char_p]
        self.id_dev.Donsee_M1VerifyPass.restype = c_long
        
        self.id_dev.Donsee_M1Read.argtypes = [c_int, c_char_p]
        self.id_dev.Donsee_M1Read.restype = c_long
        
        self.id_dev.Donsee_M1Write.argtypes = [c_int, c_char_p]
        self.id_dev.Donsee_M1Write.restype = c_long

        # 执行M1卡操作
        uid = create_string_buffer(256)
        data = create_string_buffer(128)
        
        # 1. 请求卡片
        ret = self.id_dev.Donsee_ICRequest()
        if ret != 0:
            print(f"M1 卡片请求失败，返回值:{ret}")
            return (ret, "")
            
        # 2. 防碰撞获取UID
        ret = self.id_dev.Donsee_ICAnticoll(uid)
        if ret != 0:
            print(f"M1 卡片防碰撞失败，返回值:{ret}")
            return (ret, "")
            
        # # 3. 选择卡片
        # ret = self.id_dev.Donsee_ICSelect(0x41)
        # if ret != 0:
        #     print(f"M1 卡片选择失败，返回值:{ret}")
        #     return (ret, "")
            
        # # 4. 验证密码
        # ret = self.id_dev.Donsee_M1VerifyPass(key_mode, block//4, key.encode('utf-8'))
        # if ret != 0:
        #     print(f"M1 卡片密码验证失败，返回值:{ret}")
        #     return (ret, "")
            
        # # 5. 读取数据
        # ret = self.id_dev.Donsee_M1Read(block, data)
        # if ret != 0:
        #     print(f"M1 卡片读取失败，返回值:{ret}")
        #     return (ret, "")
            
        # 返回UID和读取的数据
        # return (0, uid.value.decode('utf-8'), data.value.decode('utf-8'))
        return (0, uid.value.decode('utf-8'))
